package com.nulldev.util.security.encryptAPI_rw.impls.nacl;

import java.io.InputStream;
import java.io.OutputStream;

import com.nulldev.util.data.Variables;
import com.nulldev.util.security.encryptAPI.impls.nacl_thirdparty.NaCl;
import com.nulldev.util.security.encryptAPI_rw.api.ICipherType;
import com.nulldev.util.security.encryptAPI_rw.api.IStandardBlockingCipher;
import com.nulldev.util.security.encryptAPI_rw.api.IStandardStreamingCipher;

public class NaClSharedCipher implements IStandardBlockingCipher, IStandardStreamingCipher {

	private static final String[] CIPHER_NAMES =
		{ "NaCl", "NaCl-shared", "NaCl_shared" };

	@Override
	public String getEncryptorID() {
		return "ecr_v3.external.nacl_shared";
	}

	@Override
	public String[] getCipherNames() {
		return CIPHER_NAMES;
	}

	@Override
	public long encrypt(final InputStream is, final OutputStream os, final byte[] privateKey) {
		Variables.requireNonNull(is, "is");
		Variables.requireNonNull(os, "os");
		long count = 0;
		final NaCl.SecretBox box = new NaCl.SecretBox(Variables.requireNonNullObject(privateKey, "privateKey"));
		final byte[] b = new byte[32];
		try {
			while ((count += (is.read(b, 0, 32))) != -1) {
				box.box(b, 0, b.length);
				os.write(b, 0, 32);
			}
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
		return count;
	}

	@Override
	public long decrypt(final InputStream is, final OutputStream os, final byte[] privateKey) {
		Variables.requireNonNull(is, "is");
		Variables.requireNonNull(os, "os");
		long count = 0;
		final NaCl.SecretBox box = new NaCl.SecretBox(Variables.requireNonNullObject(privateKey, "privateKey"));
		final byte[] b = new byte[32];
		try {
			while ((count += (is.read(b, 0, 32))) != -1) {
				box.open(b, 0, b.length);
				os.write(b, 0, 32);
			}
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
		return count;
	}

	@Override
	public byte[] encrypt(final byte[] data, final byte[] key) {
		final NaCl.SecretBox box = new NaCl.SecretBox(Variables.requireNonNullObject(key, "key"));
		return box.box(data);
	}

	@Override
	public byte[] decrypt(final byte[] data, final byte[] key) {
		final NaCl.SecretBox box = new NaCl.SecretBox(Variables.requireNonNullObject(key, "key"));
		return box.open(data);
	}

	@Override
	public ICipherType getCipherType() {
		return ICipherType.PRIVATE_KEY;
	}

}
